using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DevExpress.XtraEditors;

namespace Comteck.Winforms {
  /// <summary>
  /// winform扩展方法
  /// </summary>
  public static class WinformExtensions {
    /// <summary>
    /// 执行异步添加数据
    /// </summary>
    /// <param name="synchInvoke"></param>
    /// <param name="action"></param>
    public static void InvokeMethodSync(this ISynchronizeInvoke synchInvoke, Action action) {
      if (synchInvoke == null || action == null) {
        return;
      }

      //System.Threading.Thread.Sleep(10000);
      if (synchInvoke.InvokeRequired) {
        var invoker = new Action(() => {
          action();
        });
        synchInvoke.BeginInvoke(invoker, null);
      } else {
        action();
      }
    }

    #region 查找父对象控件的名称

    /// <summary>
    /// 查找父对象控件的名称
    /// </summary>
    /// <param name="control"></param>
    /// <returns></returns>
    public static string GetParentControlName(this Control control) {
      var parent = control.Parent;

      if (parent != null && String.IsNullOrWhiteSpace(parent.Name) == false) {
        return parent.Name;
      }

      return GetParentControlName(parent);
    }

    #endregion

    #region 在当前容器范围内查询指定名称的控件

    /// <summary>
    /// 在当前容器范围内查询指定名称的控件
    /// </summary>
    /// <param name="control">父容器范围</param>
    /// <param name="controlName">控件名</param>
    /// <param name="ignoreCase">是否忽略大小写</param>
    /// <returns></returns>
    public static Control FindControlLoop(this Control control, string controlName, bool ignoreCase = false) {
      // 比较方法
      var compare = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;

      //
      foreach (Control subControl in control.Controls) {
        if (string.Equals(subControl.Name, controlName, compare)) {
          return subControl;
        }

        var targetControl = FindControlLoop(subControl, controlName, ignoreCase);

        if (targetControl != null) {
          return targetControl;
        }
      }

      return null;
    }

    #endregion

    #region 查找窗体

    /// <summary>
    /// 
    /// </summary>
    /// <param name="application"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static Form FindCurrentForm<T>(this System.Windows.Forms.Application application) where T : Form {
      return System.Windows.Forms.Application.OpenForms.OfType<T>().FirstOrDefault();
    }

    #endregion

    #region 添加拖动事件

    /// <summary>
    /// 
    /// </summary>
    /// <param name="form"></param>
    /// <returns></returns>
    public static void AddDragEvents(this List<Control> controlList) {
      controlList.ForEach(control => {
        control.AddDragEvents();
      });
    }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="form"></param>
      /// <returns></returns>
      public static void AddDragEvents(this Control control) {
      // 控件所在的表单
      var form = control.FindForm();

      //
      var headHeight = form.FormBorderStyle == FormBorderStyle.None ? 30 : 0;

      // 记录鼠标按键是否按下 
      var isMouseDown = false;

      // 记录鼠标指针的坐标 
      var mouseOffset = new Point();
      int xOffset;
      int yOffset;

      // 控件相对位置
      var controlLocation = control.GetRelativeLocation();

      control.MouseDown += (sender, e) => {
        if (e.Button == MouseButtons.Left) {
          xOffset = -e.X - SystemInformation.FrameBorderSize.Width - controlLocation.X;
          yOffset = -e.Y - SystemInformation.CaptionHeight -
          SystemInformation.FrameBorderSize.Height - controlLocation.Y + headHeight;
          mouseOffset = new Point(xOffset, yOffset);
          isMouseDown = true;
        }
      };

      control.MouseMove += (sender, e) => {
        if (isMouseDown) {
          var mousePos = Control.MousePosition;
          mousePos.Offset(mouseOffset.X, mouseOffset.Y);
          form.Location = mousePos;

          // 在最大化状态下拖动窗体，自动变成普通大小
          if (form.WindowState == FormWindowState.Maximized) {
            form.WindowState = FormWindowState.Normal;
            return;
          }
        }
      };

      control.MouseUp += (sender, e) => {
        // 确保只有鼠标左键按下并移动时，才移动窗体 
        if (e.Button == MouseButtons.Left) {
          isMouseDown = false;
        }
      };

    }

    /// <summary>
    /// 获取控件相对于form的相对位置
    /// </summary>
    /// <param name="control"></param>
    /// <returns></returns>
    public static Point GetRelativeLocation(this Control control) {
      // 当前控件的位置
      var location = control.Location;

      if (control is Form) {
        return new Point();
      }

      // 父控件
      var parent = control.Parent;

      while (parent != null && !(parent is Form)) {
        location.X = location.X + parent.Location.X;
        location.Y = location.Y + parent.Location.Y;

        parent = parent.Parent;
      }

      return location;
    }

    #endregion

    #region 模拟winform自带的头部事件

    /// <summary>
    /// 
    /// </summary>
    /// <param name="form"></param>
    /// <param name="minControl"></param>
    /// <param name="maxControl"></param>
    /// <param name="maxValue"></param>
    /// <param name="reductionValue"></param>
    /// <param name="closeControl"></param>
    /// <param name="doubleClickControls"></param>
    public static void SetMinMaxCloseEvents(this Form form,
      PictureEdit minControl, object minValue1, object minValue2,
      PictureEdit maxControl, object maxValue, object reductionValue,
      PictureEdit closeControl, object closeValue1, object closeValue2,
      List<Control> doubleClickControls,
      Action hoverAction = null, Action leaveAction = null) {

      // 指定窗体最大位置
      form.MaximumSize = GetSize(form);

      // 当前窗体
      var tmpState = FormWindowState.Normal;

      // 窗体尺寸变化，最大化按钮图片变化
      form.SizeChanged += (sender, e) => {
        // 点击最大化
        if (tmpState != FormWindowState.Maximized && form.WindowState == FormWindowState.Maximized) {
          tmpState = FormWindowState.Maximized;
          maxControl.EditValue = reductionValue;
          maxControl.ToolTip = "还原";
          //this.Text = "普通变为最大化";
        } else if (tmpState == FormWindowState.Maximized && form.WindowState == FormWindowState.Normal) {
          //窗口由最大化还原为普通
          tmpState = FormWindowState.Normal;
          maxControl.EditValue = maxValue;
          maxControl.ToolTip = "最大化";
          //this.Text = "最大化还原为普通";
        }
      };

      #region 最小化

      // 最小化
      minControl.MouseClick += (sender, e) => {
        if (e.Button == MouseButtons.Left) {
          form.WindowState = FormWindowState.Minimized;
        }
      };

      minControl.MouseEnter += (sender, e) => {
        minControl.EditValue = minValue1;
        hoverAction?.Invoke();
      };

      minControl.MouseLeave += (sender, e) => {
        minControl.EditValue = minValue2;
        leaveAction?.Invoke();
      };

      #endregion

      #region 最大化/还原

      // 最大化/还原
      maxControl.MouseClick += (sender, e) => {
        if (e.Button != MouseButtons.Left) {
          return;
        }

        switch (tmpState) {
          case FormWindowState.Normal:
          case FormWindowState.Minimized:
            form.MaximumSize = GetSize(form);
            form.WindowState = FormWindowState.Maximized;
            break;
          case FormWindowState.Maximized:
            form.WindowState = FormWindowState.Normal;
            break;
          default:
            break;
        }
      };


      maxControl.MouseEnter += (sender, e) => {
        hoverAction?.Invoke();
      };

      maxControl.MouseLeave += (sender, e) => {
        leaveAction?.Invoke();
      };

      #endregion

      #region 关闭

      // 关闭
      closeControl.MouseClick += (sender, e) => {
        if (e.Button == MouseButtons.Left) {
          form.Close();
        }
      };

      closeControl.MouseEnter += (sender, e) => {
        closeControl.EditValue = closeValue1;
        hoverAction?.Invoke();
      };

      closeControl.MouseLeave += (sender, e) => {
        closeControl.EditValue = closeValue2;
        leaveAction?.Invoke();
      };

      #endregion

      #region 双击还原

      // 双击还原
      doubleClickControls.ForEach((control) => {
        control.MouseDoubleClick += (sender, e) => {
          if (tmpState == FormWindowState.Maximized) {
            form.WindowState = FormWindowState.Normal;
          } else {
            form.MaximumSize = GetSize(form);
            form.WindowState = FormWindowState.Maximized;
          }
        };
      });

      #endregion

    }

    /// <summary>
    /// 取得窗前窗口的最大值
    /// </summary>
    /// <returns></returns>
    private static Size GetSize(Form form) {
      var result = new Size();
      result.Width = Screen.GetWorkingArea(form).Width;
      result.Height = Screen.GetWorkingArea(form).Height;
      return result;
    }

    #endregion

    #region 模拟winform拖动边框

    /// <summary>
    /// 
    /// </summary>
    /// <param name="form"></param>
    public static void AddFormMove(this Form form) {
      // 表示鼠标当前是否处于按下状态，初始值为否 
      var isMouseDown = false;

      // 表示拖动的方向，起始为None，表示不拖动
      var direction = MouseDirection.None;

      // 鼠标按下
      form.MouseDown += (sender, e) => {
        isMouseDown = true;
      };

      // 鼠标弹起，
      form.MouseUp += (sender, e) => {
        isMouseDown = false;
        //既然鼠标弹起了，那么就不能再改变窗体尺寸，拖拽方向置 none
        direction = MouseDirection.None;
      };

      // 移动
      form.MouseMove += (sender, e) => {
        //鼠标移动过程中，坐标时刻在改变 
        //当鼠标移动时横坐标距离窗体右边缘5像素以内且纵坐标距离下边缘也在5像素以内时，要将光标变为倾斜的箭头形状，同时拖拽方向direction置为MouseDirection.Declining 
        if (e.Location.X >= form.Width - 5 && e.Location.Y > form.Height - 5) {
          form.Cursor = Cursors.SizeNWSE;
          direction = MouseDirection.Declining;
        }
        //当鼠标移动时横坐标距离窗体右边缘5像素以内时，要将光标变为倾斜的箭头形状，同时拖拽方向direction置为MouseDirection.Herizontal
        else if (e.Location.X >= form.Width - 5) {
          form.Cursor = Cursors.SizeWE;
          direction = MouseDirection.Herizontal;
        }
        //同理当鼠标移动时纵坐标距离窗体下边缘5像素以内时，要将光标变为倾斜的箭头形状，同时拖拽方向direction置为MouseDirection.Vertical
        else if (e.Location.Y >= form.Height - 5) {
          form.Cursor = Cursors.SizeNS;
          direction = MouseDirection.Vertical;

        }
        //否则，以外的窗体区域，鼠标星座均为单向箭头（默认）             
        else {
          form.Cursor = Cursors.Arrow;
        }

        //设定好方向后，调用下面方法，改变窗体大小  
        ResizeWindow();
      };

      // 改变窗体大小
      void ResizeWindow() {
        //这个判断很重要，只有在鼠标按下时才能拖拽改变窗体大小，如果不作判断，那么鼠标弹起和按下时，窗体都可以改变 
        if (!isMouseDown)
          return;
        //MousePosition的参考点是屏幕的左上角，表示鼠标当前相对于屏幕左上角的坐标this.left和this.top的参考点也是屏幕，属性MousePosition是该程序的重点
        if (direction == MouseDirection.Declining) {
          //此行代码在mousemove事件中已经写过，在此再写一遍，并不多余，一定要写
          form.Cursor = Cursors.SizeNWSE;
          //下面是改变窗体宽和高的代码，不明白的可以仔细思考一下
          form.Width = Control.MousePosition.X - form.Left;
          form.Height = Control.MousePosition.Y - form.Top;
        }
        //以下同理
        if (direction == MouseDirection.Herizontal) {
          form.Cursor = Cursors.SizeWE;
          form.Width = Control.MousePosition.X - form.Left;
        } else if (direction == MouseDirection.Vertical) {
          form.Cursor = Cursors.SizeNS;
          form.Height = Control.MousePosition.Y - form.Top;
        }
          //即使鼠标按下，但是不在窗口右和下边缘，那么也不能改变窗口大小
          else {
          form.Cursor = Cursors.Arrow;
        }
      }

    }


  /// <summary>
  /// 定义一个枚举，表示拖动方向
  /// </summary>
  public enum MouseDirection {
      Herizontal,//水平方向拖动，只改变窗体的宽度        
      Vertical,//垂直方向拖动，只改变窗体的高度 
      Declining,//倾斜方向，同时改变窗体的宽度和高度        
      None//不做标志，即不拖动窗体改变大小 
    }

    #endregion

  }
}
